package battle.controllers;

import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentLinkedQueue;


import battle.gameplay.Bullet;
import battle.gameplay.Direction;

import com.jme3.asset.AssetManager;
import com.jme3.bullet.BulletAppState;
import com.jme3.bullet.collision.shapes.BoxCollisionShape;
import com.jme3.effect.ParticleEmitter;
import com.jme3.effect.ParticleMesh;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import com.jme3.scene.Spatial.CullHint;

/**
 * 
 * @author t.key
 */
public class BulletController{
	
	private Spatial bulletModel;
	private Material fireMat, smokeMat, explosionMat, crackMat;
	private final Node rootNode;
	private final BulletAppState bulletState;
	private ConcurrentLinkedQueue <Bullet> bullets = new ConcurrentLinkedQueue <Bullet>();
	
	public BulletController(AssetManager assetManager, Node rootNode, BulletAppState bulletState){
		this.rootNode = rootNode;
		this.bulletState = bulletState;
		loadBullet(assetManager);
		loadEffectMaterials(assetManager);
	}
	
	private void loadBullet(AssetManager assetManager){
		bulletModel = assetManager.loadModel("models/bullet.mesh.xml");
		Material mat = new Material(assetManager, "Common/MatDefs/Misc/SolidColor.j3md");
		mat.setColor("m_Color", ColorRGBA.DarkGray);
		bulletModel.setMaterial(mat);
	}
	
	private void loadEffectMaterials(AssetManager assetManager){
		fireMat = new Material(assetManager, "Common/MatDefs/Misc/Particle.j3md");
		fireMat.setTexture("m_Texture", assetManager.loadTexture("Effects/Explosion/flame.png"));
		
		smokeMat = new Material(assetManager, "Common/MatDefs/Misc/Particle.j3md");
		smokeMat.setTexture("m_Texture", assetManager.loadTexture("Effects/Smoke/Smoke.png"));
		
		explosionMat = new Material(assetManager, "Common/MatDefs/Misc/Particle.j3md");
		explosionMat.setTexture("m_Texture", assetManager.loadTexture("Effects/Explosion/flame.png"));
		
		crackMat = new Material(assetManager, "Common/MatDefs/Misc/Particle.j3md");
		crackMat.setTexture("m_Texture", assetManager.loadTexture("Effects/Explosion/Debris.png"));
	}
	
	private ParticleEmitter createFireEffect(){
		ParticleEmitter fire = new ParticleEmitter("fire", ParticleMesh.Type.Triangle, 20);
		fire.setMaterial(fireMat);
		fire.setImagesX(2);
		fire.setImagesY(2);
		fire.setStartColor(new ColorRGBA(1f, 0.4f, 0.05f, 1));
		fire.setEndColor(new ColorRGBA(.4f, .22f, .12f, 0f));
		fire.setStartSize(0.6f);
		fire.setEndSize(0.9f);
		fire.setLowLife(0.5f);
		fire.setHighLife(0.7f);
		fire.setRotateSpeed(3f);
		fire.setParticlesPerSec(20);
		fire.setCullHint(CullHint.Never);
		rootNode.attachChild(fire);
		return fire;
	}
	
	private ParticleEmitter createSmokeEffect(){
		ParticleEmitter smoke = new ParticleEmitter("smoke", ParticleMesh.Type.Triangle, 60);
		smoke.setMaterial(smokeMat);
		smoke.setImagesX(15);
		smoke.setImagesY(1);
		smoke.setEndColor(new ColorRGBA(0.1f, 0.1f, 0.1f, 1));
		smoke.setStartColor(new ColorRGBA(0.5f, 0.5f, 0.5f, 1));
		smoke.setStartSize(0.5f);
		smoke.setEndSize(0.7f);
		smoke.setLowLife(0.01f);
		smoke.setHighLife(0.2f);
		smoke.setGravity(-0.5f);
		smoke.setRandomAngle(true);
		smoke.setRotateSpeed(3);
		smoke.setSelectRandomImage(true);
		smoke.setVariation(0.3f);
		smoke.setParticlesPerSec(30);
		smoke.setCullHint(CullHint.Never);
		rootNode.attachChild(smoke);
		return smoke;
	}
	
	public void createBullet(float dir, Vector3f localTranslation){
		Vector3f dirVector = Direction.vector(dir);
		Vector3f locVector = localTranslation.add(dirVector.mult(1.5f).setY(1.05f));
		
		BoxCollisionShape bulletShape = new BoxCollisionShape(new Vector3f(0.1f, 0.1f, 0.1f));
		Bullet bullet = new Bullet(bulletModel.clone(), bulletShape, dirVector, locVector);
		bullet.rotate(0, dir, 0);
		bullet.setFireEffect(createFireEffect());
		bullet.setSmokeEffect(createSmokeEffect());
		bulletState.getPhysicsSpace().add(bullet);
		rootNode.attachChild(bullet);
		bullets.add(bullet);
	}
	
	public void update(final float tpf){
		for (Bullet bullet : bullets){
			if (bullet.update(tpf)){
				bulletState.getPhysicsSpace().remove(bullet);
				bullet.removeFromParent();
				bullets.remove(bullet);
			}
		}
	}
}
